package utils

import (
	"github.com/shirou/gopsutil/v4/disk"
	"os"
	"path"
	"path/filepath"
	"strings"
)

// DirSize 获取目录所占磁盘大小
func DirSize(dirPath string) (int64, error) {
	// Walk 递归遍历数据目录
	var size int64
	err := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if !info.IsDir() {
			size += info.Size()
		}
		return nil
	})
	return size, err
}

// DataFileDirSize 获取数据文件所占磁盘大小，用户注入条件回调，对数据文件进行过滤
func DataFileDirSize(dirPath string, cb func(fileName string) bool) (int64, error) {
	var size int64
	err := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if !info.IsDir() && strings.HasSuffix(info.Name(), ".data") {
			if cb != nil {
				if cb(info.Name()) {
					size += info.Size()
				}
			} else {
				size += info.Size()
			}
		}
		return nil
	})
	return size, err
}

// AvailableDiskSize 获取磁盘剩余可用空间大小
func AvailableDiskSize(dirPath string) (uint64, error) {
	diskUsage, err := disk.Usage(dirPath)
	if err != nil {
		return 0, err
	}
	return diskUsage.Free, nil
}

// CopyDir 目录数据拷贝
func CopyDir(src, dest string, exclude []string) error {
	src = NormalizationFilePathString(src)
	dest = NormalizationFilePathString(dest)
	// 目标目录不存在，创建该目录
	if _, err := os.Stat(dest); os.IsNotExist(err) {
		if err := os.MkdirAll(dest, os.ModePerm); err != nil {
			return err
		}
	}

	// 递归遍历源目录
	return filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
		path = NormalizationFilePathString(path)
		// 取出文件不带路径名称
		fileName := strings.Replace(path, src, "", 1)
		if fileName == "" {
			return nil
		}
		// 查看是否存在不包含的列表中
		for _, e := range exclude {
			matched, err := filepath.Match(e, info.Name())
			if err != nil {
				return err
			}
			if matched {
				return nil
			}
		}

		// 是目录则创建
		if info.IsDir() {
			return os.MkdirAll(filepath.Join(dest, fileName), info.Mode())
		}

		// 从源读出文件，写入目标目录
		data, err := os.ReadFile(filepath.Join(src, fileName))
		if err != nil {
			return err
		}

		return os.WriteFile(filepath.Join(dest, fileName), data, info.Mode())
	})
}

// NormalizationFilePathString  标准化路径格式
func NormalizationFilePathString(filePath string) string {
	filePathClean := path.Clean(filePath)
	filePathClean = strings.Replace(filePathClean, "\\", "/", -1)
	return filePathClean
}
